package com.ruoyi.system.service.impl;

import java.math.BigDecimal;
import java.util.*;

import com.baomidou.mybatisplus.core.conditions.query.Query;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.CommonUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.mapper.AppNewsTypesMapper;
import com.ruoyi.system.service.IAppRedPacketSendService;
import com.ruoyi.system.service.IAppTradeRecordService;
import com.ruoyi.system.service.IAppUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.system.mapper.AppRedPacketGetMapper;
import com.ruoyi.system.service.IAppRedPacketGetService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 红包领取记录Service业务层处理
 *
 * @author ruoyi
 * @date 2024-08-08
 */
@Service
public class AppRedPacketGetServiceImpl extends ServiceImpl<AppRedPacketGetMapper, AppRedPacketGet> implements IAppRedPacketGetService {
    @Autowired
    private AppRedPacketGetMapper appRedPacketGetMapper;

    @Autowired
    private IAppRedPacketSendService redPacketSendService;

    @Autowired
    private IAppTradeRecordService tradeRecordService;

    /**
     * 查询红包领取记录
     *
     * @param id 红包领取记录主键
     * @return 红包领取记录
     */
    @Override
    public AppRedPacketGet selectAppRedPacketGetById(Long id) {
        return appRedPacketGetMapper.selectAppRedPacketGetById(id);
    }

    /**
     * 查询红包领取记录列表
     *
     * @param appRedPacketGet 红包领取记录
     * @return 红包领取记录
     */
    @Override
    public List<AppRedPacketGet> selectAppRedPacketGetList(AppRedPacketGet appRedPacketGet) {
        return appRedPacketGetMapper.selectAppRedPacketGetList(appRedPacketGet);
    }

    /**
     * 新增红包领取记录
     *
     * @param appRedPacketGet 红包领取记录
     * @return 结果
     */
    @Override
    public int insertAppRedPacketGet(AppRedPacketGet appRedPacketGet) {
        appRedPacketGet.setCreateTime(DateUtils.getNowDate());
        return appRedPacketGetMapper.insertAppRedPacketGet(appRedPacketGet);
    }

    /**
     * 修改红包领取记录
     *
     * @param appRedPacketGet 红包领取记录
     * @return 结果
     */
    @Override
    public int updateAppRedPacketGet(AppRedPacketGet appRedPacketGet) {
        return appRedPacketGetMapper.updateAppRedPacketGet(appRedPacketGet);
    }

    /**
     * 批量删除红包领取记录
     *
     * @param ids 需要删除的红包领取记录主键
     * @return 结果
     */
    @Override
    public int deleteAppRedPacketGetByIds(Long[] ids) {
        return appRedPacketGetMapper.deleteAppRedPacketGetByIds(ids);
    }

    /**
     * 删除红包领取记录信息
     *
     * @param id 红包领取记录主键
     * @return 结果
     */
    @Override
    public int deleteAppRedPacketGetById(Long id) {
        return appRedPacketGetMapper.deleteAppRedPacketGetById(id);
    }

    @Autowired
    private IAppUserService userService;

    @Override
    public AjaxResult getSingleRedPacket(Long userId, AppRedPacketSend redPacketSendEntity) {
        AppRedPacketGet redPacketGet = new AppRedPacketGet();
        redPacketGet.setCreateTime(new Date());
        redPacketGet.setUserId(userId);
        redPacketGet.setPacketId(redPacketSendEntity.getId());
        redPacketGet.setMoney(redPacketSendEntity.getRemainMoney().setScale(2, BigDecimal.ROUND_HALF_UP));
        redPacketGet.setStatus(1);

        // 用户余额刷新,用户收到红包总金额刷新
        userService.updateUserMoneyByReceiveRedPacket(userId, redPacketSendEntity.getRemainMoney().setScale(2, BigDecimal.ROUND_HALF_UP));
        // 红包领取保存
        this.save(redPacketGet);
        // 红包发送记录更新
        redPacketSendEntity.setStock(redPacketSendEntity.getStock() - 1);
        redPacketSendEntity.setRemainMoney(BigDecimal.ZERO);
        if (redPacketSendEntity.getStock() == 0) {
            redPacketSendEntity.setStatus(1);
        }
        redPacketSendService.updateAppRedPacketSend(redPacketSendEntity);

        // 添加流水记录
        AppTradeRecord tradeRecord = new AppTradeRecord();
        tradeRecord.setCreateTime(new Date());
        tradeRecord.setUserId(userId);
        tradeRecord.setType(3);
        tradeRecord.setMoney(redPacketGet.getMoney().setScale(2, BigDecimal.ROUND_HALF_UP));
        tradeRecord.setAuditType(2);
        tradeRecordService.insertAppTradeRecord(tradeRecord);

        return getSendRedInfoAndGetList(userId, redPacketSendEntity.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult getGroupRedPacket(Long userId, AppRedPacketSend redPacketSendEntity) {
        QueryWrapper<AppRedPacketGet> redGetWrapper = new QueryWrapper<>();
        redGetWrapper.eq("user_id", userId);
        redGetWrapper.eq("packet_id", redPacketSendEntity.getId());
        long count = this.count(redGetWrapper);
        if (count > 0) {
            return AjaxResult.error(-1, "红包已领取过！");
        }

        AppRedPacketGet redPacketGet = new AppRedPacketGet();
        redPacketGet.setCreateTime(new Date());
        redPacketGet.setUserId(userId);
        redPacketGet.setPacketId(redPacketSendEntity.getId());

        // 记录开始的时间
        long start = System.currentTimeMillis();

        // 无限循环，当抢包时间超过100ms或者成功时退出
        boolean isEnd = false;
        while (true) {
            // 循环当前时间
            long end = System.currentTimeMillis();
            // 如果抢红包的时间已经超过了100ms,就直接返回失败
            if (end - start > 100) {
                return AjaxResult.error(-1, "抢红包失败，请重新尝试");
            }

            redPacketSendEntity = redPacketSendService.getById(redPacketSendEntity.getId());
            if (redPacketSendEntity.getStatus() > 0) {
                return AjaxResult.error(-9, "红包已领完");
            }

            BigDecimal delMoney;
            // 群红包
            if (redPacketSendEntity.getGroupType() == 0) {   // 0：普通红包
                delMoney = redPacketSendEntity.getMoney().divide(new BigDecimal(redPacketSendEntity.getShareNum().toString())).setScale(2, BigDecimal.ROUND_HALF_UP);
                redPacketGet.setMoney(delMoney);
            } else {   // 1：拼手气红包，2：口令红包
                delMoney = getRandomMoney(redPacketSendEntity.getRemainMoney(), redPacketSendEntity.getStock()).setScale(2, BigDecimal.ROUND_HALF_UP);
                if (delMoney.compareTo(BigDecimal.ZERO) == 0) {
                    return AjaxResult.error(-9, "红包已领完");
                }
                redPacketGet.setMoney(delMoney);
            }

            // 红包发送记录更新
            redPacketSendEntity.setStock(redPacketSendEntity.getStock() - 1);
            redPacketSendEntity.setRemainMoney(redPacketSendEntity.getRemainMoney().subtract(delMoney).setScale(2, BigDecimal.ROUND_HALF_UP));
            if (redPacketSendEntity.getStock() == 0) {
                redPacketSendEntity.setStatus(1);
                isEnd = true;
            }
            int oldVersion = redPacketSendEntity.getVersion();
            redPacketSendEntity.setVersion(oldVersion + 1);

            QueryWrapper<AppRedPacketSend> sendQw = new QueryWrapper<>();
            sendQw.eq("id", redPacketSendEntity.getId());
            sendQw.eq("version", oldVersion);
            boolean temp = redPacketSendService.update(redPacketSendEntity, sendQw);
            if (temp) {
                break;
            }
        }

        // 用户余额刷新,用户收到红包总金额刷新
        userService.updateUserMoneyByReceiveRedPacket(userId, redPacketGet.getMoney().setScale(2, BigDecimal.ROUND_HALF_UP));
        // 红包领取保存
        this.save(redPacketGet);

        // 添加流水记录
        AppTradeRecord tradeRecord = new AppTradeRecord();
        tradeRecord.setCreateTime(new Date());
        tradeRecord.setUserId(userId);
        tradeRecord.setType(3);
        tradeRecord.setMoney(redPacketGet.getMoney().setScale(2, BigDecimal.ROUND_HALF_UP));
        tradeRecord.setAuditType(2);
        tradeRecordService.insertAppTradeRecord(tradeRecord);

        // 红包全部领取完时计算最佳手气
        if (isEnd && redPacketSendEntity.getGroupType() == 1) {
            List<AppRedPacketGet> getRedList = this.list(new QueryWrapper<AppRedPacketGet>().eq("packet_id", redPacketSendEntity.getId()));
            BigDecimal temp = BigDecimal.ZERO;
            int betterIndex = 0;
            for (int i = 0; i < getRedList.size(); i++) {
                AppRedPacketGet getRed = getRedList.get(i);
                if (getRed.getMoney().compareTo(temp) > 0) {
                    temp = getRed.getMoney();
                    betterIndex = i;
                }
            }
            AppRedPacketGet betterGetRed = getRedList.get(betterIndex);
            betterGetRed.setStatus(1);
            this.updateById(betterGetRed);
        }

        return getSendRedInfoAndGetList(userId, redPacketSendEntity.getId());
    }

    // 每个红包最大是平均值的倍数
    private static final int TIMES = 2;

    public BigDecimal getRandomMoney(BigDecimal total, int count) {
        int totalVal = (int) (total.doubleValue() * 100); // 随机生成整数，将钱数化为整数

        Integer val;
        // 当前剩余钱数 满足0.01每人时
        if (count != 0 && totalVal / count == 1) {
            val = 1;
            count--;
            return BigDecimal.valueOf(val.longValue()).divide(BigDecimal.valueOf(100l));
        }

        if (count <= 0) {
            val = 0;
        } else if (count == 1) {
            val = totalVal;
        } else {
            int temp; //剩下的金额
            while (true) {
                // 随机生成当前金额的随机数 [0,totalVal/count),尽量平均一点
//                val = new Random().nextInt(totalVal / 2);
                // 红包最大金额为平均金额的TIMES倍
                val = new Random().nextInt(totalVal * TIMES / count);

                val = val > totalVal ? totalVal : val;
                temp = totalVal - val;
                // 判断生成的金额大于0，且剩余的钱数够剩下人平分到0.01元
                if (temp / (count - 1) >= 1 && val > 0) {
                    break;
                }
            }
        }
        return BigDecimal.valueOf(val.longValue()).divide(BigDecimal.valueOf(100l));
    }

    @Override
    public AjaxResult getSendRedInfoAndGetList(Long userId, Long redPacketId) {
        AppRedPacketSend redPacketSendEntity = redPacketSendService.getById(redPacketId);

        AppUser sendUser = userService.getById(redPacketSendEntity.getUserId());
        redPacketSendEntity.setUserName(sendUser.getUsername());
        redPacketSendEntity.setHeadImg(sendUser.getHeadImg());
        if (redPacketSendEntity.getType() == 1 && redPacketSendEntity.getGroupType() == 2)
            redPacketSendEntity.setCommand(CommonUtils.decodeNickname(redPacketSendEntity.getCommand()));

        List<AppRedPacketGet> getRedList = this.list(
                new QueryWrapper<AppRedPacketGet>()
                        .eq("packet_id", redPacketSendEntity.getId())
                        .orderByDesc("create_time")
        );

        BigDecimal currentUserGetMoney = BigDecimal.ZERO;

        for (AppRedPacketGet getEntity : getRedList) {
            AppUser getUser = userService.getById(getEntity.getUserId());
            getEntity.setUserName(getUser.getUsername());
            getEntity.setHeadImg(getUser.getHeadImg());
            getEntity.setMoney(getEntity.getMoney().setScale(2, BigDecimal.ROUND_HALF_UP));

            if (userId.equals(getEntity.getUserId())) {
                currentUserGetMoney = getEntity.getMoney().setScale(2, BigDecimal.ROUND_HALF_UP);
            }
        }
        Map<String, Object> map = new HashMap<>();
        map.put("redPacketSend", redPacketSendEntity);
        map.put("getRedList", getRedList);
        map.put("currentUserGetMoney", currentUserGetMoney);

        return AjaxResult.ok(0, "红包领取成功", map);
    }

}
